var YvanUI = top.window.YvanUI
var _ = YvanUI.lodash
var React = YvanUI.React
var toJS = YvanUI.mobx.toJS
var autorun = YvanUI.mobx.autorun
var scope
var autorunDisposer

var editor = monaco.editor.create(document.getElementById('app'), {
  value: '',
  language: 'json',
});

window.onresize = function () {
  editor.layout();
};

editor.onDidChangeModelContent(function (e) {
  applyChange();
});

function openScope(scopeParam) {
  scope = scopeParam

  const $datakey = $('#dataKey')
  $datakey.empty()
  _.forOwn(scope, (v, key) => {
    if (YvanUI.mobx.isObservable(scope[key])) {
      $('#dataKey').append("<option value=" + key + ">" + key + "</option>")
    }
  })

  $datakey.on('change', function () {
    var key = $('#dataKey').val()
    if (autorunDisposer) {
      autorunDisposer();
    }

    autorunDisposer = autorun(() => {
      var source = toJS(scope[key])
      editor.setValue(JSON.stringify(source, null, ' '))
    })
  })

  $datakey.val('vjson').trigger('change')
}

function applyChange() {
  var key = $('#dataKey').val()

  var json1
  try {
    json1 = JSON.parse(editor.getValue())
  } catch (e) {
    // 编辑器有语法错误
    console.log('js error', e)
    return
  }
  var json2 = JSON.parse(
      JSON.stringify(
          toJS(scope[key]),
          null, ' ')
  )

  var array1 = []
  deepTraverObject(json1, function (keypath) {
    array1.push(keypath + "=" + _.get(json1, keypath))
  })

  var array2 = []
  deepTraverObject(json2, function (keypath) {
    array2.push(keypath + "=" + _.get(json2, keypath))
  })

  const dif = _.difference(array1, array2)
  for (var i = 0; i < dif.length; i++) {
    var [path, value] = dif[i].split('=')
    _.set(scope[key], path, value)
  }
}


function deepTraverObjectInner(hierarchyParent, parentPath, cb) {
  _.forOwn(hierarchyParent, (v, k) => {

    const currentFullPath = parentPath ? parentPath + "." + k : k

    if (_.isPlainObject(v)) {
      deepTraverObjectInner(v, currentFullPath, cb)

    } else if (_.isArray(v)) {
      _.forEach(v, (item, idx) => {
        deepTraverObjectInner(item, currentFullPath + `[${idx}]`, cb)
      })

    } else {
      cb(currentFullPath)
    }
  })
}

/**
 * 深度遍历多层级 JSON, 传入一个 (path:string)=>void 回调
 * @param hierarchyObject
 * @param cb
 */
function deepTraverObject(hierarchyObject, cb) {
  deepTraverObjectInner(hierarchyObject, '', cb)
}
